package mornd.simpleurlhandlermapping;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
import org.springframework.web.servlet.resource.*;

import javax.annotation.PostConstruct;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

/**
 * @author: mornd
 * @dateTime: 2023/5/9 - 16:30
 */

@Configuration
@ComponentScan
public class WebConfig {

    /**
     * 注册内嵌 web 服务器
     * @return
     */
    @Bean
    public TomcatServletWebServerFactory webServerFactory() {
        return new TomcatServletWebServerFactory();
    }

    @Bean
    public DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
        return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    }

    // 声明映射器
    @Bean
    public SimpleUrlHandlerMapping handlerMapping(@Autowired ApplicationContext applicationContext) {
        // 手动设置路径映射
        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        Map<String, ResourceHttpRequestHandler> mappings = applicationContext.getBeansOfType(ResourceHttpRequestHandler.class);
        simpleUrlHandlerMapping.setUrlMap(mappings);
        return simpleUrlHandlerMapping;
    }

    // 声明适配器
    @Bean
    public HttpRequestHandlerAdapter handlerAdapter() {
        return new HttpRequestHandlerAdapter();
    }

    // 声明处理器
    @Bean("/**")
    public ResourceHttpRequestHandler resourceHttpRequestHandler() {
        ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
        handler.setLocations(Collections.singletonList(new ClassPathResource("static/")));
        handler.setResourceResolvers(new ArrayList<ResourceResolver>() {{
            // 按顺序依次解析
            // 带缓存的解析器
            add(new CachingResourceResolver(new ConcurrentMapCache("cacheMap")));
            // 可以解析压缩资源
            add(new EncodedResourceResolver());
            // 最基本也是默认的解析器
            add(new PathResourceResolver());
        }});
        return handler;
    }

    @Bean("/img/**")
    public ResourceHttpRequestHandler resourceHttpRequestHandler2() {
        ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler();
        handler.setLocations(Collections.singletonList(new ClassPathResource("images/")));
        return handler;
    }

    // 将 static/下的html文件压缩
    @PostConstruct
    public void initGzip() throws IOException {
        ClassPathResource resource = new ClassPathResource("static");
        File dir = resource.getFile();
        File[] files = dir.listFiles(pathname -> pathname.getName().endsWith(".html"));

        for (File file : files) {
            System.out.println(file);
            String gzName =  file.getAbsolutePath() + ".gz"; // 压缩文件名
            try (FileInputStream ifs = new FileInputStream(file);
                 GZIPOutputStream os = new GZIPOutputStream(new FileOutputStream(gzName))) {
                byte[] bytes = new byte[8 * 1024];
                int len;
                while ((len = ifs.read(bytes)) != -1) {
                    os.write(bytes, 0, len);
                }
            }
        }
    }

    /**
     * 欢迎页处理器
     * 它对应的适配器（SimpleControllerHandlerAdapter）
     * 通用 BeanNameUrl 的适配器，处理器也是实现 Controller 接口
     */
    @Bean
    public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext) {
        ClassPathResource resource = new ClassPathResource("static/index.html");
        return new WelcomePageHandlerMapping(null, applicationContext,
                resource, "/**");
    }

    @Bean // 搭配上面方法的welcomePage映射器使用
    public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
        return new SimpleControllerHandlerAdapter();
    }

}
